/*$Id: WidgetController.java 68 2008-03-06 00:05:29Z lrsmith $*/
package com.leetech.gwt.client;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBoxBase;
import com.google.gwt.user.client.ui.Widget;

/**
 * Generates query widgets that will be used to make a query to a database. This
 * is done by implementing
 * {@link nreldata.nbc.gwt.client.query.WidgetController.Callback}, and then
 * calling <code>fetchQueryPanelAsync</code>.
 * 
 * @author Last modified by $LastChangedBy: lrsmith $.
 * @version $Rev: 68 $ $Date: 2008-03-05 14:05:29 -1000 (Wed, 05 Mar 2008) $.
 */
public class WidgetController {

    // Static initialization--------------------------------------------
    public static String CLASS_LIST_BOX = "com.google.gwt.user.client.ui.ListBox";
    public static String CLASS_TEXT_BOX = "com.google.gwt.user.client.ui.TextBox";
    public static String CLASS_TEXT_AREA = "com.google.gwt.user.client.ui.TextArea";

    public static String CLASS_LABELED_WIDGET = "com.leetech.gwt.client.LabeledWidget";
    // Instance variables-----------------------------------------------
    /** Widgets to controlled by the widget controller. */
    private List widgets;

    // Constructors-----------------------------------------------------

    /**
     * Constructs a WidgetController and opens an RPC connection.
     */
    public WidgetController() {
        widgets = new ArrayList();
    }

    // Methods----------------------------------------------------------
    /**
     * Opens a servlet connection and returns a service object.
     */
    public static WidgetServiceAsync openService(String servletUrl) {
        // open RPC connection.
        WidgetServiceAsync widgetService = (WidgetServiceAsync) GWT
                .create(WidgetService.class);

        ServiceDefTarget endpoint = (ServiceDefTarget) widgetService;
        endpoint.setServiceEntryPoint(servletUrl);
        return widgetService;
    }

    /**
     * Populates a query panel with query widgets asynchronously using a
     * callback function.
     * 
     * @param emptyPanel
     *            The query panel to populate with widgets.
     * @param callback
     *            The callback function returning a populated query panel.
     */
    public void registerWidget(Widget widget) {
        widgets.add(widget);
    }

    /**
     * Gets the WidgetDTO states of all registered widgets.
     */
    public WidgetDTO[] getStates() {
        WidgetDTO[] dtos = new WidgetDTO[widgets.size()];
        for (int i = 0; i < widgets.size(); i++) {
            dtos[i] = new WidgetDTO();
            try {
                dtos[i].getState((Widget) widgets.get(i));
            } catch (Exception e) {
                ErrorDialogBox box = new ErrorDialogBox(e);
            }
        }
        return dtos;
    }

    /**
     * Sends widget state information to the servlet and updates widget state
     * via the servlet response.
     */
    public void syncWidgets(WidgetServiceAsync servlet) {

        // generate queryDTO objects for the query widgets
        servlet.syncWidgetDTOs(getStates(), new AsyncCallback() {

            public void onFailure(Throwable caught) {
                ErrorDialogBox box = new ErrorDialogBox(caught);
            }

            public void onSuccess(Object result) {
                WidgetDTO[] returnDtos = (WidgetDTO[]) result;
                for (int i = 0; i < returnDtos.length; i++) {
                    try {
                        returnDtos[i].setState((Widget) widgets.get(i));
                    } catch (Exception e) {
                        ErrorDialogBox box = new ErrorDialogBox(e);
                    }
                }
            }
        });
    }

    // Inner Classes ---------------------------------------------------

    public static class WidgetDTO implements IsSerializable {

        /**
         * This is the name of the field that the ListBox represents, for
         * example "Operator." They are defined in the interface {@link
         * nreldata.nbc.gwt.client.NbcConstants}.
         */
        private String name;
        private String label;
        private String type;

        /**
         * Terms whose content and number are specific to the type of search
         * widget this data comes from.
         */
        private String[] values;
        /**
         * Terms whose content and number are specific to the type of search
         * widget this data comes from.
         */
        private String[] state;

        /**
         * Constructs a WidgetDTO.
         */
        public WidgetDTO() {
            super();
            this.name = "";
            this.values = new String[]{""};
            this.type = "";
            this.state = new String[]{""};
        }

        /**
         * Gets the state of a widget and sets the DTO to that state.
         * 
         * @throws Exception
         *             if an unsupported widget is given in the argument.
         */
        private void getState(Widget widget) throws Exception {
            type = GWT.getTypeName(widget);
            if (type.equals(CLASS_LABELED_WIDGET)) {
                LabeledWidget pan = (LabeledWidget) widget;
                label = pan.getLabel();
                getState(pan.getWidget());
            } else if (type.equals(CLASS_LIST_BOX)) {
                ListBox box = (ListBox) widget;
                name = box.getName();
                List states = new ArrayList();
                values = new String[box.getItemCount()];
                for (int i = 0; i < box.getItemCount(); i++) {
                    values[i] = box.getValue(i);
                    if(box.isItemSelected(i)){
                        states.add(values[i]);
                    }
                }
                state = (String[]) states.toArray(new String[states.size()]);
            } else if (type.equals(CLASS_TEXT_BOX)
                    || type.equals(CLASS_TEXT_AREA)) {
                TextBoxBase box = (TextBoxBase) widget;
                name = box.getName();
                state = new String[]{ box.getText() };
            } else {
                throw new Exception("DTO type has chaned to unsupported type:"+ type );
            }
        }

        /**
         * Sets the state of a widget from the WidgetDTO state.
         * 
         * @throws Exception
         *             if an unsupported widget is given in the argument.
         */
        private void setState(Widget widget) throws Exception {
            
            // type checking between Widget and WidgetDTO
            if(!GWT.getTypeName(widget).equals(type) &&
            !GWT.getTypeName(widget).equals(CLASS_LABELED_WIDGET)){
                throw new Exception("Can't set widget "+
                        GWT.getTypeName(widget) +" to DTO of type "+
                        type);
            } else if (GWT.getTypeName(widget).equals(CLASS_LABELED_WIDGET)) {
                LabeledWidget pan = (LabeledWidget) widget;
                pan.setLabel(label);
              //  if (supportedClasses.contains(GWT.getTypeName(pan.getWidget()))) {
                    setState(pan.getWidget());
             //   }
            } else if (type.equals(CLASS_LIST_BOX)) {
                ListBox box = (ListBox) widget;
                int stateInd = 0;
                box.setName(name);
                box.clear();
                if(state.length>1){
                    box.setMultipleSelect(true);
                }
                for (int i = 0; i < values.length; i++) {
                    box.addItem(values[i]);
                    if(stateInd < state.length && state[stateInd].equals(values[i])){
                        box.setSelectedIndex(i);
                        stateInd++;
                    }
                }
            } else if (type.equals(CLASS_TEXT_BOX) ||
                    type.equals(CLASS_TEXT_AREA)){
                TextBoxBase box = (TextBoxBase) widget;
                box.setText(values[0]);
                box.setName(name);
            }else {
                throw new Exception(type + " is an unsupported widget class");
            }
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getLabel() {
            return label;
        }

        public void setLabel(String label) {
            this.label = label;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String[] getValues() {
            return values;
        }

        public void setValues(String[] values) {
            this.values = values;
        }

        public String[] getState() {
            return state;
        }

        public void setState(String[] state) {
            this.state = state;
        }

    }

}
